// iConfig.cpp : Defines the entry point for the application.
//

// iCaller.cpp : Defines the entry point for the application.
//

#include "stdafx.h"

#include <atlframe.h>
#include <atlcrack.h>
#include <atlmisc.h>
#include <atlscrl.h>
#include <atlctrls.h>
#include <atlwince.h>

#include <initguid.h>

#include "resourceppc.h"

#include "iConfig.h"
#include "Common.h"
#include "Settings.h"
#include "Theme.h"
#include "Util.h"
#include "ListSelectorDlg.h"

#ifdef _DEBUG
#include "crtdbg.h"
#endif

CAppModule _Module;

bool PreInit();
void PreTerminate();
void ApplyCommandLine(HWND hWnd, TCHAR* szCmdLine, bool bRemote = false);

int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
  CMessageLoop* pLoop = _Module.GetMessageLoop();
	ATLASSERT(pLoop != NULL);
	pLoop->AddMessageFilter(this);
  
  ::ZeroMemory(&m_sai, sizeof(m_sai));
  m_sai.cbSize = sizeof(m_sai);

  SHMENUBARINFO embi = { sizeof(SHMENUBARINFO), m_hWnd, SHCMBF_EMPTYBAR | SHCMBF_HIDDEN };
  ::SHCreateMenuBar(&embi);
  m_hMenubar = embi.hwndMB;

  ApplyCommandLine(m_hWnd, ::GetCommandLine());

  CString sFile = CSettings::GetAppFolder();
  sFile += m_layoutFile;
  if (!m_layout.Load(sFile))
  {
    MessageBox(LANG("ErrLoadLayout"), LANG("iConfig"), MB_OK | MB_ICONSTOP);
    return -1;
  }

  // create lists
  CRect rcList;
  GetClientRect(&rcList);
  for (int i = 0; i < m_layout.GetTabCount(); i++)
  {
    CLayoutList* pList = m_layout.GetLayout(i);
    if (pList)
      pList->Create(m_hWnd, rcList, NULL, WS_CHILD | (i == 0 ? WS_VISIBLE : 0));
    if (i == 0)
      m_activeList = pList;
  }

  // create buttons
  m_btnClose.SetImages(CTheme::GetImage(timButtonBg), CTheme::GetImage(timButtonCancel), CTheme::GetImage(timButtonDCancel));
  m_btnTabsPrev.SetImages(CTheme::GetImage(timButtonBg), CTheme::GetImage(timArrowLeft), CTheme::GetImage(timArrowLeft));
  m_btnTabs.SetImages(CTheme::GetImage(timButtonBg), CTheme::GetImage(timButtonTabs), CTheme::GetImage(timButtonDTabs));
  m_btnTabsNext.SetImages(CTheme::GetImage(timButtonBg), CTheme::GetImage(timArrowRight), CTheme::GetImage(timArrowRight));
  m_btnSave.SetImages(CTheme::GetImage(timButtonBg), CTheme::GetImage(timButtonOk), CTheme::GetImage(timButtonDOk));

  m_header.Create(m_hWnd, NULL, m_layout.GetTabName(m_activeList), WS_CHILD | WS_VISIBLE | SS_CENTER);

  m_btnClose.Create(m_hWnd, NULL, NULL, WS_CHILD | WS_VISIBLE, 0, IDCANCEL);
  m_btnTabsPrev.Create(m_hWnd, NULL, NULL, WS_CHILD | WS_VISIBLE, 0, IDC_BTN_TABS_PREV);
  m_btnTabs.Create(m_hWnd, NULL, NULL, WS_CHILD | WS_VISIBLE, 0, IDC_BTN_TABS);
  m_btnTabsNext.Create(m_hWnd, NULL, NULL, WS_CHILD | WS_VISIBLE, 0, IDC_BTN_TABS_NEXT);
  m_btnSave.Create(m_hWnd, NULL, NULL, WS_CHILD | WS_VISIBLE, 0, IDOK);

  return 0;
}

void CMainFrame::OnDestroy()
{
  PostQuitMessage(0);
}

LRESULT CMainFrame::OnCopyData(UINT, WPARAM, LPARAM lParam, BOOL&)
{
  COPYDATASTRUCT* pData = reinterpret_cast<COPYDATASTRUCT*>(lParam);
  if (pData != NULL && pData->cbData > 0 && pData->lpData != NULL)
  {
    TCHAR* szCmdLine = ::_tcsdup((const TCHAR*)pData->lpData);
    if (szCmdLine)
      ApplyCommandLine(m_hWnd, szCmdLine, true);
    ::free(szCmdLine);
  }
  return 0;
}

void CMainFrame::OnSize(UINT nType, CSize size)
{
  if (nType == SIZE_MINIMIZED)
  {
    Close();
  }
  else
  {
    CRect rcClient;
    GetClientRect(&rcClient);
    CRect rc = rcClient;

    rc.bottom = rc.top + CTheme::fntPopupHeader.size;
    m_header.MoveWindow(&rc);

    rc.top = rc.bottom;
    rc.bottom = rcClient.bottom - CTheme::iListItemSize;

    for (int i = 0; i < m_layout.GetTabCount(); i++)
    {
      CLayoutList* pList = m_layout.GetLayout(i);
      if (pList)
        pList->MoveWindow(&rc);
    }

    int btnW = rcClient.Width() / 5;

    rc.top = rc.bottom;
    rc.bottom = rcClient.bottom;
    rc.left = rcClient.left;
    rc.right = rc.left + btnW;
    m_btnClose.MoveWindow(&rc);

    rc.left = rc.right;
    rc.right = rc.left + btnW;
    m_btnTabsPrev.MoveWindow(&rc);

    rc.left = rc.right;
    rc.right = rc.left + btnW;
    m_btnTabs.MoveWindow(&rc);

    rc.left = rc.right;
    rc.right = rc.left + btnW;
    m_btnTabsNext.MoveWindow(&rc);

    rc.left = rc.right;
    rc.right = rcClient.right;
    m_btnSave.MoveWindow(&rc);
  }
}

LRESULT CMainFrame::OnActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
  ::SHHandleWMActivate(m_hWnd, wParam, lParam, &m_sai, 0);

  if (LOWORD(wParam) == WA_CLICKACTIVE || LOWORD(wParam) == WA_ACTIVE)
  {
    // Resize the main window to the size of the work area.
    UpdateWindowPosition(false);

    ShowWindow(SW_SHOWNORMAL);

    if (!m_activeList)
      m_activeList = m_layout.GetLayout(0);
    if (m_activeList)
      m_activeList->SetFocus();
  }

  return 0;
}

LRESULT CMainFrame::OnSettingChange(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
  //::SHHandleWMSettingChange(m_hWnd, wParam, lParam, &m_sai);
  UpdateWindowPosition();

  if (m_activeList)
    m_activeList->ScrollToSelection(false);

  return 0;
}

void CMainFrame::OnClose(UINT uNotifyCode, int nID, CWindow wndCtl)
{
  Close();
}

void CMainFrame::OnTabsPrev(UINT uNotifyCode, int nID, CWindow wndCtl)
{
  TabsPrev();
}

void CMainFrame::OnTabs(UINT uNotifyCode, int nID, CWindow wndCtl)
{
  Tabs();
}

void CMainFrame::OnTabsNext(UINT uNotifyCode, int nID, CWindow wndCtl)
{
  TabsNext();
}

void CMainFrame::OnSave(UINT uNotifyCode, int nID, CWindow wndCtl)
{
  Save();
}

void CMainFrame::Close()
{
  if (m_layout.IsChanged())
  {
    int res = MessageBox(LANG("SaveChanges"), LANG("iConfig"), MB_YESNO | MB_ICONQUESTION);
    if (res == IDYES)
    {
      Save();
    }
  }

  DestroyWindow();
}

void CMainFrame::TabsPrev()
{
  int idx = 0;

  if (m_activeList)
  {
    CString name = m_layout.GetTabName(m_activeList);
    idx = m_layout.GetTabIndex(name);
    if (idx < 0)
      idx = 0;
    else
    {
      idx--;
      if (idx < 0)
        idx = m_layout.GetTabCount() - 1;
    }

    m_activeList->ShowWindow(SW_HIDE);
  }
  
  m_activeList = m_layout.GetLayout(idx);
  if (m_activeList)
    m_activeList->ShowWindow(SW_SHOW);
  m_header.SetWindowText(CLanguage::Get(m_layout.GetTabName(m_activeList)));
}

void CMainFrame::Tabs()
{
  // create dialog
  CListSelectorDlg dlg;
  if (!dlg.Create(m_hWnd, NULL, LANG("Select")))
    return;

  // fill list
  m_layout.BuildTabList(*dlg.GetList());
  dlg.SetSelection(m_layout.GetTabName(m_activeList));

  // calculate animation rects
  CRect rcStart, rcEnd;
  m_btnTabs.GetWindowRect(&rcStart);
  ScreenToClient(&rcStart);
  GetClientRect(&rcEnd);

  // show dialog
  int res = dlg.DoModal(rcStart, rcEnd, SETTINGS.GetInt(sSelectorShowTime), SETTINGS.GetInt(sSelectorHideTime));

  if (res == IDOK)
  {
    int idx = m_layout.GetTabIndex(dlg.GetSelection());
    if (idx >= 0)
    {
      if (m_activeList)
        m_activeList->ShowWindow(SW_HIDE);
      m_activeList = m_layout.GetLayout(idx);
      if (m_activeList)
      {
        m_activeList->ShowWindow(SW_SHOW);
        m_activeList->SetFocus();
      }
      m_header.SetWindowText(CLanguage::Get(m_layout.GetTabName(m_activeList)));
    }
  }
}

void CMainFrame::TabsNext()
{
  int idx = 0;

  if (m_activeList)
  {
    CString name = m_layout.GetTabName(m_activeList);
    idx = m_layout.GetTabIndex(name);
    if (idx < 0)
      idx = 0;
    else
    {
      idx++;
      if (idx >= m_layout.GetTabCount())
        idx = 0;
    }

    m_activeList->ShowWindow(SW_HIDE);
  }

  m_activeList = m_layout.GetLayout(idx);
  if (m_activeList)
    m_activeList->ShowWindow(SW_SHOW);
  m_header.SetWindowText(CLanguage::Get(m_layout.GetTabName(m_activeList)));
}

void CMainFrame::Save()
{
  if (m_layout.IsChanged())
  {
    if (!m_layout.Save())
    {
      MessageBox(LANG("SaveFailed"), LANG("iConfig"), MB_OK | MB_ICONEXCLAMATION);
      return;
    }

    if (m_layout.GetInfo().appRestart)
    {
      int res = MessageBox(LANG("RestartApp"), LANG("iConfig"), MB_YESNO | MB_ICONQUESTION);
      if (res == IDYES)
      {
        const TCHAR* szClass = m_layout.GetInfo().appWndClass.IsEmpty() ? NULL : m_layout.GetInfo().appWndClass.GetString();
        const TCHAR* szTitle = m_layout.GetInfo().appWndTitle.IsEmpty() ? NULL : m_layout.GetInfo().appWndTitle.GetString();
        HWND hWnd = ::FindWindow(szClass, szTitle);
        if (hWnd)
        {
          ::DestroyWindow(hWnd);
          CString sApp;
          if (!m_layout.GetInfo().appExecutable.IsEmpty() && m_layout.GetInfo().appExecutable[0] != TEXT('\\'))
            sApp = CSettings::GetAppFolder();
          sApp += m_layout.GetInfo().appExecutable;
          if (!CreateProcess(sApp, NULL, NULL, NULL, FALSE, 0, NULL, NULL, NULL, NULL))
          {
            MessageBox(LANG("RestartFailed"), LANG("iConfig"), MB_OK | MB_ICONEXCLAMATION);
          }
        }
      }
    }
  }
  DestroyWindow();
}

void CMainFrame::UpdateWindowPosition(bool redraw)
{
  ::SHFullScreen(m_hWnd, SHFS_HIDESIPBUTTON);

  CRect rcClient;
  GetClientRect(&rcClient);
  CRect rcw;
  SystemParametersInfo(SPI_GETWORKAREA, 0, &rcw, FALSE);

  HWND hwndMB = ::SHFindMenuBar(m_hWnd);
  if (hwndMB)
  {
    RECT rc;
    ::GetWindowRect(hwndMB, &rc);
    rcw.bottom = min(rcw.bottom, rc.top);
  }
  else if (CSettings::IsSmartphone())
  { // Overlap menubar
    rcw.bottom = ::GetSystemMetrics(SM_CYSCREEN);
  }

  SIPINFO sipi = {0};
  sipi.cbSize = sizeof(sipi);
  if (::SipGetInfo(&sipi))
  {
    rcw.bottom = min(rcw.bottom, sipi.rcVisibleDesktop.bottom);
  }
  MoveWindow(rcw, redraw);
}

bool PreInit()
{
  BEGINLOG(TEXT("iConfig.log"), lsDefault);

  if (!CSettings::Initialize(SETTINGS_FILE_NAME))
  {
    ::MessageBox(::GetDesktopWindow(), TEXT("Unable to load settings!"), TEXT("iConfig"), MB_OK | MB_ICONSTOP | MB_SETFOREGROUND);
    return false;
  }
  if (!CLanguage::Initialize())
  {
    ::MessageBox(::GetDesktopWindow(), TEXT("Unable to load language file!"), TEXT("iConfig"), MB_OK | MB_ICONEXCLAMATION | MB_SETFOREGROUND);
  }
  if (!CTheme::Initialize())
  {
    ::MessageBox(::GetDesktopWindow(), LANGF(TEXT("ErrLoadTheme"), SETTINGS.GetString(sTheme)), LANG("iConfig"), MB_OK | MB_ICONSTOP | MB_SETFOREGROUND);
    return false;
  }

  return true;
}

void PreTerminate()
{
  CTheme::Terminate();
  CLanguage::Terminate();
  CSettings::Terminate();

  ENDLOG();
}

// keys:
//       -log <type>    where type is:
//                      off - no logging
//                      default - error, warning
//                      all - error, warning, info, timer
void  ApplyCommandLine(HWND hWnd, TCHAR* szCmdLine, bool bRemote)
{
  const TCHAR* token = NULL;
  TCHAR* tokenNext   = NULL;
  token = ::_tcstok(szCmdLine, TEXT(" "));
  while (token)
  {
    if (::_tcsnicmp(token, TEXT("-log"), 4) == 0)
    {
      // get next token
      token = ::_tcstok(NULL, TEXT(" "));
      if (!token)
        break;
      if (::_tcsicmp(token, TEXT("off")) == 0)
        Logger::SetSeverity(lsNone);
      else if (::_tcsicmp(token, TEXT("default")) == 0)
        Logger::SetSeverity(lsDefault);
      else if (::_tcsicmp(token, TEXT("all")) == 0)
        Logger::SetSeverity(lsAll);
    }

    // get next token
    token = ::_tcstok(NULL, TEXT(" "));
  }
}

int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPTSTR lpstrCmdLine, int nCmdShow)
{
  HRESULT hRes = CMainFrame::ActivatePreviousInstance(hInstance, lpstrCmdLine, false);

	if (FAILED(hRes) || S_FALSE == hRes)
	{
		return hRes;
	}

  CoInitializeEx(NULL, COINIT_MULTITHREADED);
	SHInitExtraControls();

	hRes = _Module.Init(NULL, hInstance);
	ATLASSERT(SUCCEEDED(hRes));

  int nRet = 0;

  try
  {
    if (PreInit())
    {
		  CMessageLoop theLoop;
		  _Module.AddMessageLoop(&theLoop);

		  CMainFrame wndMain;

		  if(wndMain.CreateEx(NULL, NULL, WS_OVERLAPPEDWINDOW, WS_EX_CAPTIONOKBTN | WS_EX_WINDOWEDGE, NULL))
		  {
        wndMain.ShowWindow(nCmdShow);

        nRet = theLoop.Run();

        _Module.RemoveMessageLoop();
      }
    }
  }
  catch(...)
  {
  }

  PreTerminate();
  CoUninitialize();

	_Module.Term();
  return nRet;
}